﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Controls;
using FlowNodeFramework.Node;
using System.IO;
using System.Windows.Media.Imaging;
using Microsoft.Win32;
using System.Windows.Media.Media3D;
using System.Diagnostics;
using FlowNodeFramework.UC;
using System.Security.Cryptography.Xml;
using System.Collections.ObjectModel;
using DataObject = System.Windows.DataObject;
using System.Drawing;
using Point = System.Windows.Point;
using Size = System.Windows.Size;

namespace FlowNodeFramework.Views
{
    public partial class MainView : Window
    {
        private Point startPoint;
        private System.Windows.Shapes.Path currentPath;
        private bool isConnecting = false;
        private bool hasConnected = false;
        private FrameworkElement fromPort;
        private List<Connection> connections = new List<Connection>();
        private List<FrameworkElement> inputPorts = new List<FrameworkElement>();

        private Control draggingNode = null;
        private Point dragOffset;

        // 最小偏移判断（每次移动距离至少大于0.5才进行更新）
        private const double MoveThreshold = 0.5;

        #region 线条宽度
        private double lineThickness = 3;
        #endregion

        #region 框选相关
        // 框选选中的起始点
        private Point? selectionStartPoint = null;

        // 存放被选中的控件
        private List<Control> selectedControls = new List<Control>();

        // 拖动相关
        private bool isDragging = false;
        private Point dragStartPoint;
        private Dictionary<Control, Point> originalPositions = new Dictionary<Control, Point>();
        #endregion

        #region 平面缩放相关
        private double _currentScale = 1.0;
        private const double ScaleStep = 0.1;
        private ScaleTransform _scaleTransform = new ScaleTransform(1.0, 1.0);
        #endregion

        #region 边界扩展相关
        double margin = 20; // 离边缘多少像素以内就扩展Canvas
        double expandEdge = 200;
        #endregion

        #region 拖拽相关
        private ContextMenu NodeMenu;
        #endregion

        public MainView()
        {
            InitializeComponent();
            InitNodeMenu();

            MainCanvas.RenderTransform = _scaleTransform;
            MainCanvas.RenderTransformOrigin = new System.Windows.Point(0.5, 0.5); // 缩放中心
        }

        #region 添加修改删除节点
        private void InitNodeMenu()
        {
            NodeMenu = new ContextMenu();
            MenuItem menuItem1 = new MenuItem() { Header = "编辑节点" };
            menuItem1.Click += NodeMenuItemEdit_Click;

            MenuItem menuItem2 = new MenuItem() { Header = "删除节点" };
            menuItem2.Click += NodeMenuItemDelete_Click;

            NodeMenu.Items.Add(menuItem1);
            NodeMenu.Items.Add(menuItem2);
        }

        private void NodeMenuItemEdit_Click(object sender, RoutedEventArgs e)
        {
            dialog.Visibility = Visibility.Visible;
        }

        private void NodeMenuItemDelete_Click(object sender, RoutedEventArgs e)
        {
            foreach (XNode node in selectedControls)
            {
                // 清除相关连线,以及连线上的输入输出点
                Border inputNodeRef = node.InputNodeRef;
                Border outputNodeRef = node.OutputNodeRef;
                List<System.Windows.Shapes.Path> paths = connections.FindAll(conn => IsChildOf(conn.FromPort, node) || IsChildOf(conn.ToPort, node)).Select(conn => conn.Path).ToList();
                // 删除连线
                paths.ForEach(path => MainCanvas.Children.Remove(path));
                connections.RemoveAll(conn => IsChildOf(conn.FromPort, node) || IsChildOf(conn.ToPort, node));
                // 删除记录的输入点位
                inputPorts.Remove(inputNodeRef);
                // 删除当前节点
                MainCanvas.Children.Remove(node);
            }
            ClearSelection();
        }

        public XNode CreateNode(string title)
        {
            var node = new XNode()
            {
                Width = 240,
                Height = 160,
                Content = title,
            };
            node.ContextMenu = NodeMenu;
            node.HeaderMouseLeftBtnDown += Child_MouseLeftButtonDown;
            node.HeaderMove += Child_MouseMove;
            node.HeaderMouseLeftBtnUp += Child_MouseLeftButtonUp;

            var outputPort = node.OutputNodeRef;
            outputPort.MouseLeftButtonDown += OutputPort_MouseLeftButtonDown;

            var inputPort = node.InputNodeRef;
            inputPorts.Add(inputPort);

            return node;
        }

        private void SetNodePos(XNode node, double x, double y)
        {
            Canvas.SetLeft(node, x);
            Canvas.SetTop(node, y);
            MainCanvas.Children.Add(node);
        }

        int idx = 3;
        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            // 获取事件发生时，鼠标所在位置
            Point point = Mouse.GetPosition(MainCanvas);
            XNode xNode = CreateNode($"Node {++idx}");
            SetNodePos(xNode, point.X, point.Y);
        }

        #endregion

        #region 框选拖动
        private void Child_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            draggingNode = sender as Control;
            if (selectedControls.Contains(draggingNode))
            {
                // 点击选中控件，准备拖动
                isDragging = true;
                dragStartPoint = e.GetPosition(MainCanvas);

                originalPositions.Clear();
                foreach (var ctrl in selectedControls)
                {
                    double left = Canvas.GetLeft(ctrl);
                    double top = Canvas.GetTop(ctrl);
                    originalPositions[ctrl] = new Point(left, top);
                }

                draggingNode.CaptureMouse();
                e.Handled = true;
            }
            else
            {
                // 点击非选中控件时清除所有选中，并选中该控件
                ClearSelection();
                SelectControl(draggingNode);

                // 手动触发拖动（点击刚选中控件开始拖动）
                isDragging = true;
                dragStartPoint = e.GetPosition(MainCanvas);

                originalPositions.Clear();
                foreach (var ctrl in selectedControls)
                {
                    double left = Canvas.GetLeft(ctrl);
                    double top = Canvas.GetTop(ctrl);
                    originalPositions[ctrl] = new Point(left, top);
                }

                draggingNode.CaptureMouse();
                e.Handled = true;
            }
        }

        private void Child_MouseMove(object sender, MouseEventArgs e)
        {
            if (isDragging && e.LeftButton == MouseButtonState.Pressed)
            {
                // 一旦有元素靠近 Left 或 Top 边缘就停止移动
                bool isAtEdge = selectedControls.Any(c => Canvas.GetLeft(c) == 0 || Canvas.GetTop(c) == 0);
                if (isAtEdge) return;

                Point currentPoint = e.GetPosition(MainCanvas);
                Vector offset = currentPoint - dragStartPoint;
                // 若移动量过小则跳过（防止更新太频繁导致界面卡顿）
                if (Math.Abs(offset.X) < MoveThreshold && Math.Abs(offset.Y) < MoveThreshold)
                    return;

                foreach (var ctrl in selectedControls)
                {
                    Point original = originalPositions[ctrl];
                    Canvas.SetLeft(ctrl, original.X + offset.X);
                    Canvas.SetTop(ctrl, original.Y + offset.Y);
                }

                UpdateConnectionsForNode(selectedControls);
            }
        }

        private void Child_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (isDragging && draggingNode != null)
            {
                isDragging = false;
                draggingNode.ReleaseMouseCapture();

                // 边界检查
                BorderExpand(selectedControls);
                draggingNode = null;
                e.Handled = true;
            }
        }

        /// <summary>
        /// 添加连线更新方法
        /// </summary>
        /// <param name="selectedControls">选中的控件</param>
        /// <param name="Xoffset">连线位置X轴的偏移量</param>
        /// <param name="Yoffset">连线位置Y轴的偏移量</param>
        private void UpdateConnectionsForNode(List<Control> selectedControls, double Xoffset = 0, double Yoffset = 0)
        {
            // 当前不存在连线的话直接结束
            if (connections.Count == 0) return;

            foreach (XNode node in selectedControls)
            {
                List<Connection> refConns = connections.FindAll(conn => IsChildOf(conn.FromPort, node) || IsChildOf(conn.ToPort, node));

                refConns.ForEach(conn =>
                {
                    Point p1 = PointAdd(GetPortCenter(conn.FromPort), new Point(Xoffset, Yoffset));
                    Point p2 = PointAdd(GetPortCenter(conn.ToPort), new Point(Xoffset, Yoffset));

                    var geometry = new PathGeometry();
                    var figure = new PathFigure { StartPoint = p1 };
                    var segment = CreateSegment("polyline", p1, p2);
                    figure.Segments.Add(segment);
                    geometry.Figures.Add(figure);
                    conn.Path.Data = geometry;
                });
            }
        }

        // 点位相加
        private Point PointAdd(Point p1, Point p2)
        {
            return new Point(p1.X + p2.X, p1.Y + p2.Y);
        }

        private bool IsChildOf(FrameworkElement child, FrameworkElement parent)
        {
            var current = child;
            while (current != null)
            {
                if (current == parent)
                    return true;
                current = VisualTreeHelper.GetParent(current) as FrameworkElement;
            }
            return false;
        }
        #endregion

        #region 线条拖动 | 线条类型切换
        private void OutputPort_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (sender is FrameworkElement outputPort)
            {
                fromPort = outputPort;
                startPoint = GetPortCenter(outputPort);

                currentPath = new System.Windows.Shapes.Path
                {
                    Stroke = Brushes.MediumPurple,
                    StrokeThickness = lineThickness,
                    Data = new PathGeometry()
                };
                currentPath.MouseLeftButtonDown += Path_MouseLeftButtonDown;
                currentPath.MouseEnter += Path_MouseEnter;
                currentPath.MouseLeave += Path_MouseLeave;

                MainCanvas.Children.Add(currentPath);
                isConnecting = true;

                e.Handled = true;
            }
        }

        private Point GetPortCenter(FrameworkElement port)
        {
            var point = new Point(port.Width / 2, port.Height / 2);
            // 将当前点相对于port的坐标转换为当前点相对于Canvas的坐标位置,Canvas会先获取point左上角的位置，然后再偏移point.X,point.Y
            var position = port.TranslatePoint(point, MainCanvas);
            return position;
        }

        private PathSegment CreateSegment(string type, Point startPoint, Point endPoint)
        {
            if (string.IsNullOrEmpty(type))
                throw new Exception("type 类型不能为空");
            PathSegment segment;
            if (type == "polyline")
            {
                if (startPoint.X <= endPoint.X - 40) // 两边距离大于40
                {
                    double centerX = (startPoint.X + endPoint.X) / 2;
                    var polyline = new PolyLineSegment
                    {
                        Points = new PointCollection()
                        {
                            new Point(centerX,startPoint.Y),
                            new Point(centerX,endPoint.Y),
                            new Point(endPoint.X,endPoint.Y)    // 终点
                        }
                    };
                    segment = polyline;
                }
                else
                {
                    double centerY = (startPoint.Y + endPoint.Y) / 2;
                    var polyline = new PolyLineSegment
                    {
                        Points = new PointCollection()
                        {
                            new Point(startPoint.X + 20,startPoint.Y),
                            new Point(startPoint.X + 20,centerY),
                            new Point(endPoint.X - 20,centerY),
                            new Point(endPoint.X - 20,endPoint.Y),
                            new Point(endPoint.X,endPoint.Y)    // 终点
                        }
                    };
                    segment = polyline;
                }
            }
            else
            {
                var bezier = new BezierSegment
                {
                    Point1 = new Point(startPoint.X + 50, startPoint.Y),
                    Point2 = new Point(endPoint.X - 50, endPoint.Y),
                    Point3 = endPoint
                };
                segment = bezier;
            }

            return segment;
        }
        #endregion

        #region 线条高亮以及删除
        private void Path_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (sender is System.Windows.Shapes.Path path)
            {
                currentPath = path;
            }
        }

        private void Path_MouseEnter(object sender, MouseEventArgs e)
        {
            if (sender is System.Windows.Shapes.Path path)
            {
                path.Stroke = Brushes.Orange;
                path.StrokeThickness = lineThickness;
                path.Cursor = Cursors.Hand;
            }
        }

        private void Path_MouseLeave(object sender, MouseEventArgs e)
        {
            if (sender is System.Windows.Shapes.Path path)
            {
                path.Stroke = Brushes.MediumPurple;
                path.StrokeThickness = lineThickness;
            }
        }
        #endregion

        #region Canvas边界扩张
        public void BorderExpand(List<Control> controls)
        {
            // 一旦有元素靠近 Left 或 Top 边缘就停止移动
            bool isAtLeftEdge = selectedControls.Any(c => Canvas.GetLeft(c) - margin < 0);
            bool isAtRightEdge = selectedControls.Any(c => Canvas.GetLeft(c) + c.ActualWidth + margin > MainCanvas.ActualWidth);

            bool isAtTopEdge = selectedControls.Any(c => Canvas.GetTop(c) - margin < 0);
            bool isAtBottomEdge = selectedControls.Any(c => Canvas.GetTop(c) + c.ActualHeight + margin > MainCanvas.ActualHeight);

            if (isAtLeftEdge)
            {
                // 所有子元素右移 offset
                foreach (UIElement child in MainCanvas.Children)
                {
                    if (child is not System.Windows.Shapes.Path)
                    {
                        double oldLeft = Canvas.GetLeft(child); // 这里如果child是Path的话，这里获得的left坐标是NaN
                        Canvas.SetLeft(child, oldLeft + expandEdge);
                    }
                }
                // 增加Canvas宽度
                MainCanvas.Width = MainCanvas.ActualWidth + expandEdge;

                // 移动所有连线
                List<Control> selectedControlBak = new List<Control>(selectedControls);
                SelectAllControls();
                UpdateConnectionsForNode(selectedControls, expandEdge, 0);
                selectedControls = selectedControlBak;
            }

            if (isAtRightEdge)
            {
                MainCanvas.Width = MainCanvas.ActualWidth + expandEdge;
            }

            if (isAtTopEdge)
            {
                // 所有子元素下移 offset
                foreach (UIElement child in MainCanvas.Children)
                {
                    if (child is not System.Windows.Shapes.Path)
                    {
                        double oldTop = Canvas.GetTop(child);
                        Canvas.SetTop(child, oldTop + expandEdge);
                    }
                }

                // 增加Canvas高度
                MainCanvas.Height = MainCanvas.ActualHeight + expandEdge;

                // 移动所有连线
                List<Control> selectedControlBak = new List<Control>(selectedControls);
                SelectAllControls();
                UpdateConnectionsForNode(selectedControls, 0, expandEdge);
                selectedControls = selectedControlBak;
            }

            if (isAtBottomEdge)
            {
                MainCanvas.Height = MainCanvas.ActualHeight + expandEdge;
            }
        }
        #endregion

        #region Canvas保存为图片
        public void SaveCanvasAsImage(Canvas canvas, string filePath)
        {
            // 测量并排列 Canvas（确保它是“准备好”的）
            Size size = new Size(canvas.ActualWidth, canvas.ActualHeight);
            canvas.Measure(size);
            canvas.Arrange(new Rect(size));

            // 创建 RenderTargetBitmap
            RenderTargetBitmap rtb = new RenderTargetBitmap(
                (int)size.Width,
                (int)size.Height,
                144d, 144d, // DPI
                PixelFormats.Pbgra32);

            rtb.Render(canvas);

            // 编码为 PNG
            PngBitmapEncoder pngEncoder = new PngBitmapEncoder();
            pngEncoder.Frames.Add(BitmapFrame.Create(rtb));

            // 保存到文件
            using (FileStream fs = new FileStream(filePath, FileMode.Create))
            {
                pngEncoder.Save(fs);
            }
        }

        #endregion

        #region Canvas缩放
        private void Window_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) // Ctrl + 滚轮缩放
            {
                if (e.Delta > 0)
                    _currentScale += ScaleStep;
                else
                    _currentScale -= ScaleStep;

                _currentScale = Math.Max(0.1, Math.Min(10.0, _currentScale)); // 限制缩放范围

                _scaleTransform.ScaleX = _currentScale;
                _scaleTransform.ScaleY = _currentScale;
            }
        }
        #endregion

        #region 框选功能|线条拖动
        private void MainCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            // 如果拖动中，忽略框选
            if (isDragging) return;

            selectionStartPoint = e.GetPosition(MainCanvas);

            SelectionRectangle.Visibility = Visibility.Visible;
            Canvas.SetLeft(SelectionRectangle, selectionStartPoint.Value.X);
            Canvas.SetTop(SelectionRectangle, selectionStartPoint.Value.Y);
            SelectionRectangle.Width = 0;
            SelectionRectangle.Height = 0;

            MainCanvas.CaptureMouse();
            // 清空之前的选中
            ClearSelection();

            e.Handled = true;
        }

        private void MainCanvas_MouseMove(object sender, MouseEventArgs e)
        {
            // 线条拖动逻辑处理
            if (isConnecting && currentPath != null)
            {
                Point currentPoint = e.GetPosition(MainCanvas);
                Vector offset = currentPoint - startPoint;
                // 若移动量过小则跳过（防止更新太频繁导致界面卡顿）
                if (Math.Abs(offset.X) < MoveThreshold && Math.Abs(offset.Y) < MoveThreshold)
                    return;

                var geometry = new PathGeometry();
                var figure = new PathFigure { StartPoint = startPoint };
                var segment = CreateSegment("polyline", startPoint, currentPoint);
                figure.Segments.Add(segment);
                geometry.Figures.Add(figure);
                currentPath.Data = geometry;
            }

            // 框选逻辑处理
            if (selectionStartPoint.HasValue && e.LeftButton == MouseButtonState.Pressed && !isDragging)
            {
                Point currentPoint = e.GetPosition(MainCanvas);

                double x = Math.Min(currentPoint.X, selectionStartPoint.Value.X);
                double y = Math.Min(currentPoint.Y, selectionStartPoint.Value.Y);
                double width = Math.Abs(currentPoint.X - selectionStartPoint.Value.X);
                double height = Math.Abs(currentPoint.Y - selectionStartPoint.Value.Y);

                Canvas.SetLeft(SelectionRectangle, x);
                Canvas.SetTop(SelectionRectangle, y);
                SelectionRectangle.Width = width;
                SelectionRectangle.Height = height;

                e.Handled = true;
            }
        }

        /// <summary>
        /// 查找引脚的所在节点
        /// </summary>
        /// <param name="control"></param>
        /// <returns></returns>
        public XNode FindPinParent(DependencyObject control)
        {
            if (VisualTreeHelper.GetParent(control) is XNode node)
            {
                return node;
            }
            return FindPinParent(VisualTreeHelper.GetParent(control));
        }

        private void MainCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            // 线条拖动逻辑处理
            if (isConnecting && currentPath != null)
            {
                Point mousePos = e.GetPosition(MainCanvas);

                FrameworkElement nearestPort = null;
                double minDist = double.MaxValue;
                XNode xNode = FindPinParent(fromPort);
                Border inputNodeRef = xNode.InputNodeRef;

                foreach (var port in inputPorts)
                {
                    if (port == inputNodeRef)
                        continue;

                    Point portCenter = GetPortCenter(port);
                    double dist = (portCenter - mousePos).Length;
                    if (dist < minDist)
                    {
                        minDist = dist;
                        nearestPort = port;
                    }
                }

                if (nearestPort != null && minDist < 30) // 连线和接口的可吸附距离
                {
                    Point endPoint = GetPortCenter(nearestPort);

                    var geometry = new PathGeometry();
                    var figure = new PathFigure { StartPoint = startPoint };
                    var segment = CreateSegment("polyline", startPoint, endPoint);
                    figure.Segments.Add(segment);
                    geometry.Figures.Add(figure);
                    currentPath.Data = geometry;

                    connections.Add(new Connection
                    {
                        FromPort = fromPort,
                        ToPort = nearestPort,
                        Path = currentPath
                    });
                }
                else
                {
                    MainCanvas.Children.Remove(currentPath); // 拖空则移除
                }

                isConnecting = false;
                currentPath = null;
                fromPort = null;
                hasConnected = false;
            }

            // 框选结束逻辑处理
            if (!selectionStartPoint.HasValue) return;
            if (isDragging) return;

            MainCanvas.ReleaseMouseCapture();

            Rect selectionRect = new Rect(
                Canvas.GetLeft(SelectionRectangle),
                Canvas.GetTop(SelectionRectangle),
                SelectionRectangle.Width,
                SelectionRectangle.Height);

            SelectionRectangle.Visibility = Visibility.Collapsed;

            selectedControls.Clear();

            foreach (UIElement child in MainCanvas.Children)
            {
                if (child == SelectionRectangle) continue;

                if (child is Control ctrl) // 这里使用 Framework 而不是 Control 原因是，对于Border，Rectangle这类Shape类型的控件不属于Control类的子类
                {
                    double left = Canvas.GetLeft(ctrl);
                    double top = Canvas.GetTop(ctrl);
                    double width = ctrl.ActualWidth;
                    double height = ctrl.ActualHeight;

                    Rect childRect = new Rect(left, top, width, height);

                    if (selectionRect.IntersectsWith(childRect))
                    {
                        SelectControl(ctrl);
                    }
                    else
                    {
                        ClearSelectionStyle(ctrl);
                    }
                }
            }

            selectionStartPoint = null;

            e.Handled = true;
        }
        #endregion

        #region 选中辅助
        private void SelectAllControls()
        {
            selectedControls.Clear();
            foreach (var child in MainCanvas.Children)
            {
                if (child is XNode node)
                {
                    selectedControls.Add(node);
                }
            }
        }

        private void SelectControl(Control ctrl)
        {
            if (!selectedControls.Contains(ctrl))
            {
                selectedControls.Add(ctrl);
                ApplySelectionStyle(ctrl);
            }
        }

        private void ApplySelectionStyle(Control control)
        {
            if (control != null && control is XNode node)
            {
                node.Focused = true;
            }
        }

        private void ClearSelectionStyle(Control control)
        {
            if (control != null && control is XNode node)
            {
                node.Focused = false;
            }
        }

        private void ClearSelection()
        {
            foreach (var ctrl in selectedControls)
            {
                ClearSelectionStyle(ctrl);
            }
            selectedControls.Clear();
        }
        #endregion

        #region 快捷键以及右键菜单
        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.S && Keyboard.Modifiers == ModifierKeys.Control)
            {
                SaveFileDialog saveFileDialog = new SaveFileDialog();
                bool? flag = saveFileDialog.ShowDialog();
                if (flag == null || flag.Value == false) return;
                string filePath = saveFileDialog.FileName;
                SaveCanvasAsImage(MainCanvas, filePath);
            }
            else if (e.Key == Key.Back && currentPath != null)
            {
                connections.RemoveAll(conn => conn.Path == currentPath);
                MainCanvas.Children.Remove(currentPath);
            }
        }

        #endregion

        #region 控件拖拽
        private void ToolboxTree_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (e.Source is TreeView treeView)
            {
                if (treeView.SelectedItem == null) return;

                NodeItem? nodeItem = treeView.SelectedItem as NodeItem;
                if (nodeItem.NodeType == NodeType.Child)
                {
                    XNode xNode = CreateNode(nodeItem.Name);

                    // 创建拖拽数据，可以是控件的某种标识
                    DataObject dragData = new DataObject("XNode", xNode);

                    DragDrop.DoDragDrop(treeView, dragData, DragDropEffects.Copy);
                }
            }
        }

        private void Canvas_DragOver(object sender, DragEventArgs e)
        {
            // 必须设置拖拽效果才能正常拖拽
            if (e.Data.GetDataPresent("XNode"))
            {
                e.Effects = DragDropEffects.Copy;
            }
            else
            {
                e.Effects = DragDropEffects.None;
            }
        }

        private void Canvas_Drop(object sender, DragEventArgs e)
        {
            Point point = e.GetPosition(MainCanvas);
            XNode? node = e.Data.GetData("XNode") as XNode;
            SetNodePos(node, point.X, point.Y);
        }

        #endregion
    }
}
